package gui.view;

import generated.business.world.WorldService;
import generated.domain.avatar.Avatar;
import generated.domain.room.Room;
import generated.domain.world.World;
import gui.Activator;
import gui.IImageKeys;
import gui.ResourceManager;
import gui.action.KickAction;
import gui.action.OpenRoomAction;
import gui.action.PrivateChatAction;
import gui.entity.AvatarEntity;
import gui.entity.RoomEntity;
import gui.entity.WorldEntity;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.part.ViewPart;

import vworld.Client;

public class WorldsView extends ViewPart {
	public static final String ID = "gui.view.WorldsView";

	private TreeViewer worldsViewer;

	private KickAction kickAction;

	private OpenRoomAction openRoomAction;

	private PrivateChatAction chatAction;

	private class WorldsViewContentProvider implements
			IStructuredContentProvider, ITreeContentProvider {

		public Object[] getElements(Object inputElement) {
			List<WorldEntity> entityList = new ArrayList<WorldEntity>();
			for (World w : ((WorldService) inputElement).getWorlds()) {
				entityList.add(new WorldEntity(w));
			}
			return entityList.toArray(new WorldEntity[entityList.size()]);
		}

		public void dispose() {
		}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		}

		public Object[] getChildren(Object parentElement) {
			if (parentElement instanceof WorldEntity) {
				WorldEntity worldEntity = (WorldEntity) parentElement;
				List<RoomEntity> entityList = new ArrayList<RoomEntity>();
				for (Room r : worldEntity.getWorld().rooms) {
					entityList.add(new RoomEntity(r));
				}
				return entityList.toArray(new RoomEntity[entityList.size()]);
			}

			if (parentElement instanceof RoomEntity) {
				RoomEntity roomEntity = (RoomEntity) parentElement;
				List<AvatarEntity> entityList = new ArrayList<AvatarEntity>();
				for (Avatar a : Client.ROOM_SERVICE.getInsideAvatars(roomEntity
						.getRoom())) {
					entityList.add(new AvatarEntity(a));
				}
				return entityList.toArray(new AvatarEntity[entityList.size()]);
			}
			return null;
		}

		public Object getParent(Object element) {
			return null;
		}

		public boolean hasChildren(Object element) {
			if (element instanceof WorldEntity) {
				WorldEntity worldEntity = (WorldEntity) element;
				return (worldEntity.getWorld().rooms.length > 0);
			}

			if (element instanceof RoomEntity) {
				RoomEntity roomEntity = (RoomEntity) element;
				return (Client.ROOM_SERVICE.getInsideAvatars(roomEntity
						.getRoom()).length > 0);
			}
			return false;
		}
	}

	private class WorldsViewLabelProvider extends LabelProvider implements
			IColorProvider {
		public String getText(final Object element) {
			if (element instanceof WorldEntity) {
				WorldEntity worldEntity = (WorldEntity) element;
				return (worldEntity.getWorld().name);
			} else if (element instanceof RoomEntity) {
				RoomEntity roomEntity = (RoomEntity) element;
				return (roomEntity.getRoom().name);
			} else if (element instanceof AvatarEntity) {
				Avatar avatar = ((AvatarEntity) element).getAvatar();
				if (avatar.state) {
					return (avatar.name);
				} else {
					return (avatar.name + " (disconnected)");
				}
			}
			return "[NONAME]";
		}

		public Image getImage(final Object element) {
			if (element instanceof AvatarEntity) {
				Avatar avatar = ((AvatarEntity) element).getAvatar();
				if (Client.AVATAR_SERVICE.getUserRoleByAvatarName(avatar.name)
						.equalsIgnoreCase("administrator")) {
					return ResourceManager.getPluginImage(Activator
							.getDefault(), IImageKeys.ADMIN);
				}
				if (avatar.mood.equalsIgnoreCase("happy")) {
					return ResourceManager.getPluginImage(Activator
							.getDefault(), IImageKeys.HAPPY);
				}
				if (avatar.mood.equalsIgnoreCase("laughing")) {
					return ResourceManager.getPluginImage(Activator
							.getDefault(), IImageKeys.LAUGHING);
				}
				if (avatar.mood.equalsIgnoreCase("sad")) {
					return ResourceManager.getPluginImage(Activator
							.getDefault(), IImageKeys.SAD);
				}
				if (avatar.mood.equalsIgnoreCase("worried")) {
					return ResourceManager.getPluginImage(Activator
							.getDefault(), IImageKeys.WORRIED);
				}
				if (avatar.mood.equalsIgnoreCase("scared")) {
					return ResourceManager.getPluginImage(Activator
							.getDefault(), IImageKeys.SCARED);
				}
			}
			return null;
		}

		public Color getBackground(Object element) {
			return null;
		}

		public Color getForeground(Object element) {
			if (element instanceof AvatarEntity) {
				Avatar avatar = ((AvatarEntity) element).getAvatar();
				if (Client.AVATAR_SERVICE.getUserRoleByAvatarName(avatar.name)
						.equalsIgnoreCase("administrator")
						&& avatar.state) {
					return Display.getCurrent().getSystemColor(SWT.COLOR_RED);
				} else if (!avatar.state) {
					return Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
				}
			}
			return null;
		}
	}

	public void createPartControl(Composite parent) {
		worldsViewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.BORDER);
		worldsViewer.setContentProvider(new WorldsViewContentProvider());
		worldsViewer.setLabelProvider(new WorldsViewLabelProvider());
		worldsViewer.setInput(createModel());

		makeActions();
		hookContextMenu();
		hookDoubleClickAction();

		getSite().setSelectionProvider(worldsViewer);
	}

	public void setFocus() {
		worldsViewer.getControl().setFocus();
	}

	public Object createModel() {
		return Client.WORLD_SERVICE;
	}

	private void makeActions() {
		kickAction = new KickAction(worldsViewer, "Kick");
		openRoomAction = new OpenRoomAction(worldsViewer);
		chatAction = new PrivateChatAction(worldsViewer);
	}

	private void hookContextMenu() {
		MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
		menuMgr.setRemoveAllWhenShown(true);
		menuMgr.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				WorldsView.this.fillContextMenu(manager);
			}
		});
		Menu menu = menuMgr.createContextMenu(worldsViewer.getControl());
		worldsViewer.getControl().setMenu(menu);
		getSite().registerContextMenu(menuMgr, worldsViewer);
	}

	private void fillContextMenu(final IMenuManager manager) {
		IStructuredSelection selection = (IStructuredSelection) worldsViewer
				.getSelection();
		if (selection != null
				&& selection.getFirstElement() instanceof AvatarEntity) {
			Object object = selection.getFirstElement();
			Avatar avatar = ((AvatarEntity) object).getAvatar();
			if (!Client.AVATAR_SERVICE.getUserRoleByAvatarName(avatar.name)
					.equalsIgnoreCase("administrator")
					&& avatar.state) {
				manager.add(kickAction);
			}
		}

		if (selection != null
				&& selection.getFirstElement() instanceof RoomEntity) {
			manager.add(openRoomAction);
		}
	}

	private void hookDoubleClickAction() {
		worldsViewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				IStructuredSelection selection = (IStructuredSelection) event
						.getSelection();
				if (!selection.isEmpty()) {
					Object object = selection.getFirstElement();
					if (object instanceof RoomEntity) {
						openRoomAction.run();
					} else if (object instanceof AvatarEntity) {
						chatAction.run();
					}
				}
			}
		});
	}

	public TreeViewer getWorldsViewer() {
		return worldsViewer;
	}
}